﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using IPC.Communication.BasicFramework;
using IPC.Communication.Core;
using IPC.Communication.Core.Address;
using IPC.Communication.Serial;

namespace IPC.Communication.ModBus
{
    public class ModbusInfo
    {
        public const byte ReadCoil = 1;

        public const byte ReadDiscrete = 2;

        public const byte ReadRegister = 3;

        public const byte ReadInputRegister = 4;

        public const byte WriteOneCoil = 5;

        public const byte WriteOneRegister = 6;

        public const byte WriteCoil = 15;

        public const byte WriteRegister = 16;

        public const byte WriteMaskRegister = 22;

        public const byte FunctionCodeNotSupport = 1;

        public const byte FunctionCodeOverBound = 2;

        public const byte FunctionCodeQuantityOver = 3;

        public const byte FunctionCodeReadWriteException = 4;

        private static void CheckModbusAddressStart(ModbusAddress mAddress, bool isStartWithZero)
        {
            if (!isStartWithZero)
            {
                if (mAddress.Address < 1)
                {
                    throw new Exception(StringResources.Language.ModbusAddressMustMoreThanOne);
                }
                mAddress.Address--;
            }
        }

        public static OperateResult<byte[][]> BuildReadModbusCommand(string address, ushort length, byte station, bool isStartWithZero, byte defaultFunction)
        {
            try
            {
                ModbusAddress mAddress = new ModbusAddress(address, station, defaultFunction);
                CheckModbusAddressStart(mAddress, isStartWithZero);
                return BuildReadModbusCommand(mAddress, length);
            }
            catch (Exception ex)
            {
                return new OperateResult<byte[][]>(ex.Message);
            }
        }

        public static OperateResult<byte[][]> BuildReadModbusCommand(ModbusAddress mAddress, ushort length)
        {
            List<byte[]> list = new List<byte[]>();
            if (mAddress.Function == 1 || mAddress.Function == 2 || mAddress.Function == 3 || mAddress.Function == 4 )
            {
                OperateResult<int[], int[]> operateResult = HslHelper.SplitReadLength(mAddress.Address, length, (ushort)((mAddress.Function == 1 || mAddress.Function == 2) ? 2000 : 120));
                for (int i = 0; i < operateResult.Content1.Length; i++)
                {
                    list.Add(new byte[6]
				{
					(byte)mAddress.Station,
					(byte)mAddress.Function,
					BitConverter.GetBytes(operateResult.Content1[i])[1],
					BitConverter.GetBytes(operateResult.Content1[i])[0],
					BitConverter.GetBytes(operateResult.Content2[i])[1],
					BitConverter.GetBytes(operateResult.Content2[i])[0]
				});
                }
            }
            else
            {
                list.Add(new byte[6]
			{
				(byte)mAddress.Station,
				(byte)mAddress.Function,
				BitConverter.GetBytes(mAddress.Address)[1],
				BitConverter.GetBytes(mAddress.Address)[0],
				BitConverter.GetBytes(length)[1],
				BitConverter.GetBytes(length)[0]
			});
            }
            return OperateResult.CreateSuccessResult(list.ToArray());
        }

        public static OperateResult<byte[]> BuildWriteBoolModbusCommand(string address, bool[] values, byte station, bool isStartWithZero, byte defaultFunction)
        {
            try
            {
                ModbusAddress mAddress = new ModbusAddress(address, station, defaultFunction);
                CheckModbusAddressStart(mAddress, isStartWithZero);
                return BuildWriteBoolModbusCommand(mAddress, values);
            }
            catch (Exception ex)
            {
                return new OperateResult<byte[]>(ex.Message);
            }
        }

        public static OperateResult<byte[]> BuildWriteBoolModbusCommand(string address, bool value, byte station, bool isStartWithZero, byte defaultFunction)
        {
            try
            {
                if (address.IndexOf('.') <= 0)
                {
                    ModbusAddress mAddress = new ModbusAddress(address, station, defaultFunction);
                    CheckModbusAddressStart(mAddress, isStartWithZero);
                    return BuildWriteBoolModbusCommand(mAddress, value);
                }
                int num = Convert.ToInt32(address.Substring(address.IndexOf('.') + 1));
                if (num < 0 || num > 15)
                {
                    return new OperateResult<byte[]>(StringResources.Language.ModbusBitIndexOverstep);
                }
                int num2 = 1 << num;
                int num3 = ~num2;
                if (!value)
                {
                    num2 = 0;
                }
                return BuildWriteMaskModbusCommand(address.Substring(0, address.IndexOf('.')), (ushort)num3, (ushort)num2, station, isStartWithZero, 22);
            }
            catch (Exception ex)
            {
                return new OperateResult<byte[]>(ex.Message);
            }
        }

        public static OperateResult<byte[]> BuildWriteBoolModbusCommand(ModbusAddress mAddress, bool[] values)
        {
            try
            {
                byte[] array = SoftBasic.BoolArrayToByte(values);
                byte[] array2 = new byte[7 + array.Length];
                array2[0] = (byte)mAddress.Station;
                array2[1] = (byte)mAddress.Function;
                array2[2] = BitConverter.GetBytes(mAddress.Address)[1];
                array2[3] = BitConverter.GetBytes(mAddress.Address)[0];
                array2[4] = (byte)(values.Length / 256);
                array2[5] = (byte)(values.Length % 256);
                array2[6] = (byte)array.Length;
                array.CopyTo(array2, 7);
                return OperateResult.CreateSuccessResult(array2);
            }
            catch (Exception ex)
            {
                return new OperateResult<byte[]>(ex.Message);
            }
        }

        public static OperateResult<byte[]> BuildWriteBoolModbusCommand(ModbusAddress mAddress, bool value)
        {
            byte[] array = new byte[6]
		{
			(byte)mAddress.Station,
			(byte)mAddress.Function,
			BitConverter.GetBytes(mAddress.Address)[1],
			BitConverter.GetBytes(mAddress.Address)[0],
			0,
			0
		};
            if (value)
            {
                array[4] = byte.MaxValue;
                array[5] = 0;
            }
            else
            {
                array[4] = 0;
                array[5] = 0;
            }
            return OperateResult.CreateSuccessResult(array);
        }

        public static OperateResult<byte[]> BuildWriteWordModbusCommand(string address, byte[] values, byte station, bool isStartWithZero, byte defaultFunction)
        {
            try
            {
                ModbusAddress modbusAddress = new ModbusAddress(address, station, defaultFunction);
                if (modbusAddress.Function == 3)
                {
                    modbusAddress.Function = defaultFunction;
                }
                CheckModbusAddressStart(modbusAddress, isStartWithZero);
                return BuildWriteWordModbusCommand(modbusAddress, values);
            }
            catch (Exception ex)
            {
                return new OperateResult<byte[]>(ex.Message);
            }
        }

        public static OperateResult<byte[]> BuildWriteWordModbusCommand(string address, short value, byte station, bool isStartWithZero, byte defaultFunction)
        {
            try
            {
                ModbusAddress modbusAddress = new ModbusAddress(address, station, defaultFunction);
                if (modbusAddress.Function == 3)
                {
                    modbusAddress.Function = defaultFunction;
                }
                CheckModbusAddressStart(modbusAddress, isStartWithZero);
                return BuildWriteOneRegisterModbusCommand(modbusAddress, value);
            }
            catch (Exception ex)
            {
                return new OperateResult<byte[]>(ex.Message);
            }
        }

        public static OperateResult<byte[]> BuildWriteWordModbusCommand(string address, ushort value, byte station, bool isStartWithZero, byte defaultFunction)
        {
            try
            {
                ModbusAddress modbusAddress = new ModbusAddress(address, station, defaultFunction);
                if (modbusAddress.Function == 3)
                {
                    modbusAddress.Function = defaultFunction;
                }
                CheckModbusAddressStart(modbusAddress, isStartWithZero);
                return BuildWriteOneRegisterModbusCommand(modbusAddress, value);
            }
            catch (Exception ex)
            {
                return new OperateResult<byte[]>(ex.Message);
            }
        }

        public static OperateResult<byte[]> BuildWriteMaskModbusCommand(string address, ushort andMask, ushort orMask, byte station, bool isStartWithZero, byte defaultFunction)
        {
            try
            {
                ModbusAddress modbusAddress = new ModbusAddress(address, station, defaultFunction);
                if (modbusAddress.Function == 3)
                {
                    modbusAddress.Function = defaultFunction;
                }
                CheckModbusAddressStart(modbusAddress, isStartWithZero);
                return BuildWriteMaskModbusCommand(modbusAddress, andMask, orMask);
            }
            catch (Exception ex)
            {
                return new OperateResult<byte[]>(ex.Message);
            }
        }

        public static OperateResult<byte[]> BuildWriteWordModbusCommand(ModbusAddress mAddress, byte[] values)
        {
            byte[] array = new byte[7 + values.Length];
            array[0] = (byte)mAddress.Station;
            array[1] = (byte)mAddress.Function;
            array[2] = BitConverter.GetBytes(mAddress.Address)[1];
            array[3] = BitConverter.GetBytes(mAddress.Address)[0];
            array[4] = (byte)(values.Length / 2 / 256);
            array[5] = (byte)(values.Length / 2 % 256);
            array[6] = (byte)values.Length;
            values.CopyTo(array, 7);
            return OperateResult.CreateSuccessResult(array);
        }

        public static OperateResult<byte[]> BuildWriteMaskModbusCommand(ModbusAddress mAddress, ushort andMask, ushort orMask)
        {
            return OperateResult.CreateSuccessResult(new byte[8]
		{
			(byte)mAddress.Station,
			(byte)mAddress.Function,
			BitConverter.GetBytes(mAddress.Address)[1],
			BitConverter.GetBytes(mAddress.Address)[0],
			BitConverter.GetBytes(andMask)[1],
			BitConverter.GetBytes(andMask)[0],
			BitConverter.GetBytes(orMask)[1],
			BitConverter.GetBytes(orMask)[0]
		});
        }

        public static OperateResult<byte[]> BuildWriteOneRegisterModbusCommand(ModbusAddress mAddress, short value)
        {
            return OperateResult.CreateSuccessResult(new byte[6]
		{
			(byte)mAddress.Station,
			(byte)mAddress.Function,
			BitConverter.GetBytes(mAddress.Address)[1],
			BitConverter.GetBytes(mAddress.Address)[0],
			BitConverter.GetBytes(value)[1],
			BitConverter.GetBytes(value)[0]
		});
        }

        public static OperateResult<byte[]> BuildWriteOneRegisterModbusCommand(ModbusAddress mAddress, ushort value)
        {
            return OperateResult.CreateSuccessResult(new byte[6]
		{
			(byte)mAddress.Station,
			(byte)mAddress.Function,
			BitConverter.GetBytes(mAddress.Address)[1],
			BitConverter.GetBytes(mAddress.Address)[0],
			BitConverter.GetBytes(value)[1],
			BitConverter.GetBytes(value)[0]
		});
        }

        public static OperateResult<byte[]> ExtractActualData(byte[] response)
        {
            try
            {
                if (response[1] >= 128)
                {
                    return new OperateResult<byte[]>(GetDescriptionByErrorCode(response[2]));
                }
                if (response.Length > 3)
                {
                    return OperateResult.CreateSuccessResult(SoftBasic.ArrayRemoveBegin(response, 3));
                }
                return OperateResult.CreateSuccessResult(new byte[0]);
            }
            catch (Exception ex)
            {
                return new OperateResult<byte[]>(ex.Message);
            }
        }

        public static byte[] PackCommandToTcp(byte[] modbus, ushort id)
        {
            byte[] array = new byte[modbus.Length + 6];
            array[0] = BitConverter.GetBytes(id)[1];
            array[1] = BitConverter.GetBytes(id)[0];
            array[4] = BitConverter.GetBytes(modbus.Length)[1];
            array[5] = BitConverter.GetBytes(modbus.Length)[0];
            modbus.CopyTo(array, 6);
            return array;
        }

        public static byte[] ExplodeTcpCommandToCore(byte[] modbusTcp)
        {
            return modbusTcp.RemoveBegin(6);
        }

        public static byte[] ExplodeRtuCommandToCore(byte[] modbusRtu)
        {
            return modbusRtu.RemoveLast(2);
        }

        public static byte[] PackCommandToRtu(byte[] modbus)
        {
            return SoftCRC16.CRC16(modbus);
        }

        public static byte[] TransModbusCoreToAsciiPackCommand(byte[] modbus)
        {
            byte[] inBytes = SoftLRC.LRC(modbus);
            byte[] array = SoftBasic.BytesToAsciiBytes(inBytes);
            return SoftBasic.SpliceArray<byte>(new byte[1]
		{
			58
		}, array, new byte[2]
		{
			13,
			10
		});
        }

        public static OperateResult<byte[]> TransAsciiPackCommandToCore(byte[] modbusAscii)
        {
            try
            {
                if (modbusAscii[0] != 58 || modbusAscii[modbusAscii.Length - 2] != 13 || modbusAscii[modbusAscii.Length - 1] != 10)
                {
                    return new OperateResult<byte[]>
                    {
                        Message = StringResources.Language.ModbusAsciiFormatCheckFailed + modbusAscii.ToHexString(' ')
                    };
                }
                byte[] array = SoftBasic.AsciiBytesToBytes(modbusAscii.RemoveDouble(1, 2));
                if (!SoftLRC.CheckLRC(array))
                {
                    return new OperateResult<byte[]>
                    {
                        Message = StringResources.Language.ModbusLRCCheckFailed + array.ToHexString(' ')
                    };
                }
                return OperateResult.CreateSuccessResult(array.RemoveLast(1));
            }
            catch (Exception ex)
            {
                return new OperateResult<byte[]>
                {
                    Message = ex.Message + modbusAscii.ToHexString(' ')
                };
            }
        }

        public static OperateResult<ModbusAddress> AnalysisAddress(string address, byte defaultStation, bool isStartWithZero, byte defaultFunction)
        {
            try
            {
                ModbusAddress modbusAddress = new ModbusAddress(address, defaultStation, defaultFunction);
                if (!isStartWithZero)
                {
                    if (modbusAddress.Address < 1)
                    {
                        throw new Exception(StringResources.Language.ModbusAddressMustMoreThanOne);
                    }
                    modbusAddress.Address--;
                }
                return OperateResult.CreateSuccessResult(modbusAddress);
            }
            catch (Exception ex)
            {
                return new OperateResult<ModbusAddress>
                {
                    Message = ex.Message
                };
            }
        }

        public static string GetDescriptionByErrorCode(byte code)
        {
            switch (code)
            {
                case 1:
                    return StringResources.Language.ModbusTcpFunctionCodeNotSupport;
                case 2:
                    return StringResources.Language.ModbusTcpFunctionCodeOverBound;
                case 3:
                    return StringResources.Language.ModbusTcpFunctionCodeQuantityOver;
                case 4:
                    return StringResources.Language.ModbusTcpFunctionCodeReadWriteException;
                default:
                    return StringResources.Language.UnknownError;
            }
        }
    }
}
